package cn.wolfcode.luowowo.service.impl;

import cn.wolfcode.luowowo.cache.service.IUserInfoRedisService;
import cn.wolfcode.luowowo.domain.UserInfo;
import cn.wolfcode.luowowo.exception.LogicException;
import cn.wolfcode.luowowo.repository.UserInfoRepository;
import cn.wolfcode.luowowo.service.IUserInfoService;
import cn.wolfcode.luowowo.util.AssertUtil;
import cn.wolfcode.luowowo.util.Consts;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.List;
import java.util.UUID;

@Service
//@Transactional mongodb事务必须复制集方式
public class UserInfoServiceImpl implements IUserInfoService {

    // service在core项目中,配置位置在api项目中,后续mgrsite也会用到core项目
    // 那么若在这个地方注入配置属性,后续在mgrsite配置文件中添加2个配置
    // 如何实现通用呢?
    // 发送短信功能(获取配置文件中的网关接口地址和秘钥)
    //@Value("${sms.url}")
    //private String smsUrl;
    //@Value("${sms.appKey}")
    //private String appKey;


    //Spring-boot集成redis持久化数据库
    @Autowired
    private UserInfoRepository repository;

    @Autowired
    private IUserInfoRedisService userInfoRedisService;


    @Override
    public void save(UserInfo userInfo) {

        userInfo.setId(null);
        repository.save(userInfo);
    }

    @Override
    public void delete(String id) {

        repository.deleteById(id);
    }

    @Override
    public void update(UserInfo userInfo) {

        repository.save(userInfo);
    }

    @Override
    public UserInfo get(String id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public List<UserInfo> listAll() {
        return repository.findAll();
    }

    /**
     *  手机号校验
     * @param phone
     * @return
     */
    @Override
    public boolean checkPhone(String phone) {

        // 校验手机号是否存在
        UserInfo userInfo = repository.findByPhone(phone);
        // 有值就true ,无值false
        return userInfo != null;
    }

    // 向手机里发送短信
    @Override
    public void sendVerifyCode(String phone, String smsUrl, String appKey) {

        // 1.创建验证码,编辑短信
        String code = UUID.randomUUID().toString()
                .replace("-", "").substring(0, 4);//4位数验证码

        StringBuilder sb = new StringBuilder(80);
        sb.append("您注册的验证码是:").append(code).append("请您在")
                .append(Consts.VERIFY_CODE_VAI_TIME).append("分钟之内使用!");

        // 2.发送短信@ToDo
        System.out.println(sb.toString());//假装发送短信

        // 通过①实现短信功能麻烦,若更换网关时,代码需要改变的多(这种方式称硬编码)
        // 如何灵活实现? 在application.properties里通过配置方式实现
        // ①实现向手机里发送短信功能:(如何用java发送http请求)
        /*String url = "https://way.jd.com/chuangxin/dxjk?"+
                "mobile="+phone+"&content=【闫雪松】"+sb.toString()+"&"+
                "appkey=9d5583ce6e5596f7f7ed4f1f7f5d26ca";*/
        // ②Spring里提供的一个类:RestTemplate
        RestTemplate restTemplate = new RestTemplate();

        // ③返回字符串格式数据(注意这里的内容content这个值必须字符串中括号这种的)
        // 参数1:请求url[url中有参数占位符] 参数2:返回值类型 参数4:请求需要参数 参数5:秘钥
        //String ret = restTemplate.getForObject(smsUrl, String.class,
         //       phone, "【闫雪松】",appKey);
        // 在后台查看发送短信的状态
        //System.out.println(ret);
        // ④发送状态:给浏览器页面提示
        //if(!ret.contains("Success")){
        //    throw new LogicException("短信发送失败!");
        //}

        // 3.将短信验证码缓存到redis中
        userInfoRedisService.setVerifyCode(phone,code);

    }

    // 用户注册(带入进来的参数)
    @Override
    public void regist(String phone, String nickname, String password, String rpassword, String verifyCode) {

        // 1.判断传入参数是否为null
        // ①断言Assert判读参数的,而我们要返回一个错误提示
        AssertUtil.hasLength(phone,"手机号码不能为空");
        AssertUtil.hasLength(nickname,"昵称不能为空");
        AssertUtil.hasLength(password,"密码不能为空");
        AssertUtil.hasLength(rpassword,"确认密码不能为空");
        AssertUtil.hasLength(verifyCode,"验证码不能为空");

        // 2.判读两次输入密码是否一致
        AssertUtil.isEquals(password,rpassword,"两次输入的密码不一致!");
        // 3.判断手机号码是否符合格式@TODO(自己写)



        // 4.判断手机号是否一致
        if(this.checkPhone(phone)){
            throw new LogicException("该手机号已经被注册!");
        }

        // 5.判断验证码是否正确
        String code = userInfoRedisService.getVerifyCode(phone);
        // ①如果验证码为空 或者缓存中的验证码和页面传过来的验证码不相等,提示
        if(code == null || !code.equalsIgnoreCase(verifyCode)){
            throw new LogicException("验证码失效或错误!");
        }

        // 6.注册
        UserInfo userInfo = new UserInfo();

        userInfo.setNickname(nickname);
        userInfo.setPhone(phone);
        userInfo.setEmail("");
        userInfo.setPassword(password);
        userInfo.setLevel(1);
        userInfo.setCity("");
        userInfo.setHeadImgUrl("/images/default.jpg");
        userInfo.setInfo("");
        //状态:默认值(关机字段要自己控制)
        userInfo.setState(UserInfo.STATE_NORMAL);


        // 在保存到数据库之前可能挂掉(不是我们代码原因,可能是系统的原因)
        // 或者是有bug导致的异常(这个"模拟系统异常"就会返回前端页面,用户看得到)
        // 这种异常不必要让用户看到,怎么处理?
        //throw new RuntimeException("----------模拟系统异常----------");

        // 持久化到数据库
        this.save(userInfo);
    }


    // 登录功能的实现
    @Override
    public UserInfo login(String username, String password) {

        // 0.password此处是需要加密的

        // 前台传过来的参数是否为空(只要是前台传过来的参数就需要判断)

        // 1.通过手机号从数据库获取当前用户信息(username是手机号)
        UserInfo userInfo = repository.findByPhone(username);

        // 2.用户对象是否为null,若为空没登录,给出提示,若不为空,登录成功,提示
        if (userInfo == null || !password.equals(userInfo.getPassword())){
            throw new LogicException("账号或密码错误");
        }


        return userInfo;
    }

    // 通过城市名称查询用户集合
    @Override
    public List<UserInfo> queryByCity(String city) {
        return repository.findByCity(city);
    }

}
